package thread;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: wx
 * Date: 2024-02-14
 * Time: 21:42
 *
 *
 *
 *
 ReentrantLock
 synchronized  (在上古java 中,synchronized 不够强壮也不够强大,也没有各种优化  ReentrantLock 就是用来实现可重入锁的选择[历史遗留])
 可重入 锁
 ReentrantLock
 相对于传统的锁,这个对象提供了两个方法
 lock
 unlock
 这个写法就容易引起,加锁之后,会忘记解锁.
 在 unlock 之前,触发了 return 或者 异常,就可能会引起 unlock 执行不到了
 正确使用 ReentrantLock 就要把 unlock 放到 finally 中
   既然有了 synchronized ,为啥还要有  ReentrantLock ?
    1. ReentrantLock 提供了一个 trylock 操作
       lock 直接进行加锁,如果加锁不成功,就要阻塞
       trylock ,尝试进行加锁,如果加锁不成,不阻塞,直接返回 FALSE  (通过 trylock 提供了更多的可操作性空间)
    2. ReentrantLock 提供了公平锁的实现 (用过队列记录加锁线程的先后顺序)
        synchronized 是非公平锁
       ReentrantLock 构造方法中 填写参数,就可以设置成公平锁
    3. 搭配的等待通知机制不同
      对于 synchronized,搭配 wait/notify
      对于 ReentrantLock, 搭配 Condition 类 (功能比 wait/notify 略强一些).
 */

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

/**
  信号量 Semaphore                                                  xx 就是信号量,表示"可用资源的个数"
  一般的 停车场门口都有一个电子牌 ~~ 就会显示出当前剩余 xx 个车位            申请一个可用资源,就会使数字 +1,这个操作 就称为 P 操作
                              开进去一个车,上述数字会 +1              释放一个可用资源,就会使数字 -1,这个操作 就称为 V 操作
                              开出去一个车,上述数字会 -1                   如果数值为 0,就继续 P 操作, P 操作就会阻塞
                         等上述数字为 0 了,你就开不进去了
                          要么在门口等,要么去找下一个停车场

                         信号量也是操作系统内部给咱们提供的一机制
                         操作系统对应的 API 被 JVM 封装了,就可以通过 java 代码 来调用这里的相关操作了

 所谓的锁,本质上也是一种特殊的信号量
 锁,可以认为就是计数值为 1 的信号量                      信号量是更广义的锁

 释放状态,就是 1
 加锁状态,就是 0
 对于这种 非 0 即 1 的信号量,称为 "二元信号量"
 */
public class ThreadDemo36 {
    public static void main1(String[] args) throws InterruptedException {
        Semaphore semaphore = new Semaphore(1);// 一共有1个可用资源

        semaphore.acquire();//进行申请.
        System.out.println("P 操作");
        semaphore.acquire();
        System.out.println("P 操作");
        semaphore.acquire();
        System.out.println("P 操作");
        semaphore.release();//进行释放.
    }


    private static int count = 0;
    public static void main(String[] args) throws InterruptedException {


        Semaphore semaphore = new Semaphore(1);

        Thread t1 = new Thread(() ->{
            for (int i = 0; i < 50000; i++) {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                count++;
                semaphore.release();
            }
        });

        Thread t2 = new Thread(() ->{
            for (int i = 0; i < 50000; i++) {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                count++;
                semaphore.release();
            }
        });
        t1.start();
        t1.join();
        t2.start();
        t2.join();

        System.out.println("count = " + count);
    }
}
/*
如何 确保线程安全
1.synchronized
2.ReentrantLock
3. CAS(原子类)
4.Semaphore   (用于更加复杂的场景,实现生产者,消费者模型)
                               定义两个信号量,一个用来表示队列中有多少个可以被消费的元素      sem1
                                           另一个用来表示队列中有多少个可以放置新元素的空间  sem2

                                           生产一个元素,sem1.V(), sem2.P().
                                           消费一个元素,sem1.P(), sem2.V().
*/



